package sg.edu.nus.iss.cerberus.engine;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;

import sg.edu.nus.iss.cerberus.engine.TestEngineObjectCreator;
import sg.edu.nus.iss.cerberus.model.CClass;
import sg.edu.nus.iss.cerberus.model.CConstructor;
import sg.edu.nus.iss.cerberus.model.CMemberMethod;
import sg.edu.nus.iss.cerberus.model.CMemberVariable;

/**
 * 
 * @author Priyanka
 * 
 */
public class TestEngineParser {

	private IJavaProject javaProject;
	private IType typeInCompUnit;

	public TestEngineParser(IJavaProject javaProject, IType typeInCompUnit) {
		super();
		this.javaProject = javaProject;
		this.typeInCompUnit = typeInCompUnit;
	}

	public CClass parseCompilationUnit() {

		TestEngineObjectCreator objCreator = new TestEngineObjectCreator();
		HashMap<String, ArrayList<CMemberMethod>> methodHash = new HashMap<String, ArrayList<CMemberMethod>>();
		ArrayList<CMemberVariable> fieldArray = new ArrayList<CMemberVariable>();
		ArrayList<CConstructor> constructorArray = new ArrayList<CConstructor>();
		CClass classobj = null;

		try {
			if (javaProject != null && typeInCompUnit != null) {
				IPackageFragment[] packages = javaProject.getPackageFragments();
				for (IPackageFragment mypackage : packages) {
					if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
						objCreator.createCPackage(mypackage);
					}
				}

				ASTParser parser = ASTParser.newParser(AST.JLS3);
				parser.setSource(typeInCompUnit.getSource().toCharArray());
				CompilationUnit cu = (CompilationUnit) parser.createAST(null);
				cu.recordModifications();

				List<AbstractTypeDeclaration> types = cu.types();
				for (AbstractTypeDeclaration type : types) {
					if (type.getNodeType() == ASTNode.TYPE_DECLARATION) {
						// Class def found										
						List<BodyDeclaration> bodies = type.bodyDeclarations();

						for (BodyDeclaration body : bodies) {

							if (body.getNodeType() == ASTNode.FIELD_DECLARATION) {
								FieldDeclaration field = (FieldDeclaration) body;
								fieldArray.add(objCreator.createCField(field));
							} else if (body.getNodeType() == ASTNode.METHOD_DECLARATION) {

								MethodDeclaration method = (MethodDeclaration) body;
								if (type.getName()
										.toString()
										.equalsIgnoreCase(
												method.getName().toString())) {
									constructorArray.add(objCreator
											.createCConstructor(method));
								} else {
									if (methodHash.get(method.getName()
											.toString()) != null) {
										methodHash.get(
												method.getName().toString())
												.add(objCreator
														.createCMethod(method));

									} else {

										if (objCreator.createCMethod(method) != null) {
											ArrayList<CMemberMethod> newCMethod = new ArrayList<CMemberMethod>();
											CMemberMethod tempobj = objCreator
													.createCMethod(method);
											newCMethod.add(tempobj);
											methodHash.put(method.getName()
													.toString(), newCMethod);
										}
									}
								}
							}
						}
						classobj = objCreator.createCCLass(type, methodHash,
								fieldArray, constructorArray);
					}
				}
			}
		} catch (Exception e) {
			System.out.print(e);
		}
		return classobj;
	}

}
